设计模式沉思录(九)之 装饰器模式

设计模式沉思录(九)之 装饰器模式

装饰器模式(Decorator Pattern)

允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装

动态地给一个对象附加额外的职责。装饰者为功能的扩展提供了一个比使用子类继承更加灵活的选择

本文整理自四人帮著作:Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素)

介绍

意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活
在一个功能的基础上添加新功能,除了继承,我们还可以使用组合。即把A类当做B类的一个属性,在B类中使用A类的方法。从而实现B类对A类功能的继承。这种组合的模式比继承更加的灵活。这个就是装饰者模式的基础。

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

何时使用:在不想增加很多子类的情况下扩展类。

如何解决:将具体功能职责划分,同时继承装饰者模式。

关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

应用实例:
1.IO流中。在InputStream外面套上一层InputStreamReader,再套上一层BufferedReader。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销

注意事项:可代替继承。

实现

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。

RedShapeDecorator 是实现了 ShapeDecorator 的实体类。

步骤 1 创建shape接口:

1
2
3
public interface Shape {
void draw();
}

步骤 2 创建实现接口的 实体类Rectangle和Circle。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Rectangle implements Shape {

@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
//Circle.java
public class Circle implements Shape {

@Override
public void draw() {
System.out.println("Shape: Circle");
}
}

步骤 3 (关键)创建实现了 Shape 接口的 抽象装饰类

内部有个装饰对象属性,构造时需引入

1
2
3
4
5
6
7
8
9
10
11
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;//内部有个装饰对象属性

public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}

public void draw(){
decoratedShape.draw();
}
}

步骤 4 (关键)创建扩展了 ShapeDecorator 类的 实体装饰类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RedShapeDecorator extends ShapeDecorator {

public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);//传入shape构造 带有shape属性
}

@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);//带有redBorder
}

private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}

步骤 5 使用 RedShapeDecorator 来装饰 Shape 对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DecoratorPatternDemo {
public static void main(String[] args) {

Shape circle = new Circle();

Shape redCircle = new RedShapeDecorator(new Circle());//通过传入shape到装饰器构造一个修饰后的redCir

Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();

System.out.println("\nCircle of red border");
redCircle.draw();

System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}

总结:

一般情况:新建shape接口,circle接口继承shape接口,redcirle实体类实现circle接口

装饰器模式:
1.新建shape接口,
2.抽象类ShapeDecorator实现shape接口,并且其构造方法接收shape实例。
3.RedShapeDecorator实体装饰类继承ShapeDecorator 类(不同的实现类可实现不同的,继承自shape的方法,以体现诸如color等特点)

优点:若我想修改color,则只需要修改RedShapeDecorator,不用修改shape。
同样,若我只想修改shape,也不用去修改color。
此处输入图片的描述

  • Component接口

这个是一个抽象组件,是原始的最核心的接口,是被装饰者的抽象

  • ConcreteComponent类。

    这个类实现了Component接口,是具体的被装饰组件。在这个是最核心,最原始,最基本的组件。是具体的被装饰的组件。他实现了Component接口中的核心Operation方法。

  • Decorator抽象类。

    这类一般是个抽象类。是所有装饰者的父类,他实现了Component接口。它里面有一个私有的Component类型的属性!!!。在构造方法中初始化这个属性。在实现Component的Operation方法的时候调用的是他的Component属性的Operation方法。这个抽象类中这个组件就像上面的Decorator。

  • ConcreteDecorator类 装饰者具体实现类。

    这个是具体的装饰者类。继承自Decorator类。并且在每一个ConcreteDecorator里中有一个私有的新功能方法。然后在重写父类的Operation方法的时候。可以根据新添加的方法的执行位置,在super.Operation()之前或者之后调用本类的修饰方法(就可以体现清除不同实现的区别了)。灵活的向被修饰的类中添加新功能。

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(path))));

1
Shape redRectangle = new RedShapeDecorator(new Circle());

类似

IO流是 在path下的File中读出数据封装成一个FileInputStream流,然后被InputStreamReader装饰成一个Reader流,然后被BufferedReader装饰成为一个带缓冲的Reader。每一层封装都是对原始流的一次装饰,动态的 并且独立地 向原始的文件流中添加职责与功能。最后成为一种我们可以很方便的处理的流。

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2019 Jae's blog All Rights Reserved.

UV : | PV :